﻿using System;
using System.Collections.Generic;
using Lucene.Linq.Mapping;
using Lucene.Linq.VSTests.Helpers;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;

namespace Lucene.Linq.VSTests
{
    public static class SampleGenerator
    {
        private static readonly Random R = new Random();

        public static IEnumerable<Sample> GetRandom(int n)
        {
            return GetRandom(n, null);
        }

        public static IEnumerable<Sample> GetRandom(int n, Action<Sample> modifier)
        {
            int i = 0;
            while (n > i)
            {
                var s = new Sample
                            {
                                CaptainInteger = R.Next(),
                                MrString = R.String(10),
                                SargeantInteger = (float)R.NextDouble(),
                                BobDoublina = R.NextDouble()
                            };
                if (modifier != null)
                {
                    modifier(s);
                }
                yield return s;
                i++;
            }
        }
    }

    [Document]
    public class Sample : IEquatable<Sample>, IHit, IComparable
    {
        [Field(FieldIndex.Tokenized, FieldStore.Yes, Analyzer = typeof(SimpleAnalyzer), IsKey = true, IsDefault = true,
            IsSortable = true)]
        public string MrString { get; set; }

        [Field(FieldIndex.Tokenized, FieldStore.Yes, Analyzer = typeof(StandardAnalyzer), IsDefault = true,
            IsSortable = true)]
        public int CaptainInteger { get; set; }

        [Field(FieldIndex.Tokenized, FieldStore.Yes, Analyzer = typeof(StandardAnalyzer))]
        public float SargeantInteger { get; set; }

        [Field(FieldIndex.Tokenized, FieldStore.Yes, Analyzer = typeof(StandardAnalyzer))]
        public double BobDoublina { get; set; }

        #region IEquatable<Sample> Members

        public bool Equals(Sample other)
        {
            return MrString == other.MrString &&
                   CaptainInteger == other.CaptainInteger && SargeantInteger == other.SargeantInteger
                   && BobDoublina == other.BobDoublina;
        }

        #endregion

        #region Comparers

        public static SampleComparer<int> GetIntegerComparer()
        {
            return new SampleComparer<int>(s => s.CaptainInteger);
        }

        public static SampleComparer<string> GetStringComparer()
        {
            return new SampleComparer<string>(s => s.MrString);
        }

        public static SampleComparer<double> GetDoubleComparer()
        {
            return new SampleComparer<double>(s => s.BobDoublina);
        }

        #endregion

        #region IHit Members

        public int DocumentId { get; set; }

        public float Relevance { get; set; }

        #endregion

        public IEnumerator<string> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
        /// </summary>
        /// <returns>
        /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than <paramref name="obj"/>. Zero This instance is equal to <paramref name="obj"/>. Greater than zero This instance is greater than <paramref name="obj"/>. 
        /// </returns>
        /// <param name="obj">An object to compare with this instance. </param><exception cref="T:System.ArgumentException"><paramref name="obj"/> is not the same type as this instance. </exception><filterpriority>2</filterpriority>
        public int CompareTo(object obj)
        {
            return String.CompareOrdinal(((Sample)obj).MrString, MrString);
        }
    }

    public class SampleComparer<T> : Comparer<Sample>
    {
        private readonly Comparer<T> _comparer;
        private readonly Func<Sample, T> _getter;


        public SampleComparer(Func<Sample, T> getter)
            : this(getter, Comparer<T>.Default)
        { }

        public SampleComparer(Func<Sample, T> getter, Comparer<T> comparer)
        {
            _getter = getter;
            _comparer = comparer;
        }

        public override int Compare(Sample x, Sample y)
        {
            return _comparer.Compare(_getter(x), _getter(y));
        }

        public Func<Sample, Sample, bool> ToComparer()
        {
            return (a, b) => Compare(a, b) == 0;
        }
    }
}